//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<cached_file.inl>
///	@path	~/src/database/store/
///	@date	2007/12/04
///	@desc	Cached file accessing.

#pragma once

#include "lib/math/math_ext.h"

#include "database/store/cached_file.h"

namespace xeres {

	// CachedFile
	inline CachedFile::CachedFile( RefWeak<IFile> file , size_t buffer )
		: m_file( file ) , m_buffered( max<size_t>( buffer , 1024 ) ) , m_current( 0 )
	{
		// at least 1k buffer
		m_buffer = static_cast<byte*>( _aligned_malloc( m_buffered , ALIGN_SIZE ) );
		Flush();
	}

	// ~CachedFile
	inline CachedFile::~CachedFile( void )
	{
		_aligned_free( m_buffer );
	}

	// Next
	inline bool CachedFile::Next( ushort step_in /*= 1 */ )
	{
		if( ( m_current + step_in ) >= m_buffered )
			return false;
		m_current += step_in;
		return true;
	}

	// Prev
	inline bool CachedFile::Prev( ushort step_back /*= 1 */ )
	{
		if( step_back > m_current )
			return false;
		m_current -= step_back;
		return true;
	}

	// Current
	inline const byte * CachedFile::Current( void ) const
	{
		return m_buffer + m_current;
	}

	// Flush
	inline size_t CachedFile::Flush( uchar rollback /*= 0 */ )
	{
		if( rollback )
		{
			// save roll back
			memcpy( m_buffer , m_buffer + (m_buffered - rollback) , rollback );
		}
		m_current = 0;
		m_buffered = m_file->Read( m_buffer + rollback , m_buffered - rollback );
		if( m_buffered == 0 )
		{
			m_buffer[0] = 0;
		}
		return m_buffered;
	}

	// eof
	inline bool CachedFile::eof( void ) const
	{
		return m_buffered == 0;
	}

	// operator*
	inline byte CachedFile::operator * ( void ) const
	{
		return *Current();
	}

	// operator[]
	inline byte CachedFile::operator [] ( uchar index )
	{
		if( m_current + index >= m_buffered )
			Flush( (uchar)( m_buffered - m_current ) );
		if( m_buffered == 0 )
			return 0;
		return Current()[ index ];
	}

	// operator+=
	inline void CachedFile::operator += ( size_t count )
	{
		if( count == 0 )
			return;

		if( m_current + count >= m_buffered )
		{
			// read next buffer
			do 
			{
				size_t new_pos = (m_current + count) - m_buffered;
				size_t buffered = Flush();
				if( count < buffered )
					m_current = new_pos;

			} while( m_current + count >= m_buffered && m_buffered != 0 );
		}
		else
		{
			Next( (ushort)count );
		}
	}

	// operator++
	inline void CachedFile::operator ++ ( void )
	{
		if( m_current + 1 == m_buffered )
		{
			Flush( 0 );
		}
		else
		{
			++m_current;
		}
	}

} // namespace xeres

